package com.ims.util;

import io.jsonwebtoken.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.Date;

/**
 * @author: zk
 * @date: 2022/8/31 20:56
 */
@Component
public class JwtUtil {
    @Value("${security.jwt.secretKey}")
    private String secretKey;

    // 过期时间
    private Duration accessTokenExpiration = Duration.ofSeconds(30);
    private Duration refreshTokenExpiration = Duration.ofMinutes(1);

    /**
     * 生成accessToken
     * @param subject
     * @return
     */
    public String generateAccessToken(String subject) {
        return generate(subject, accessTokenExpiration);
    }

    /**
     * 生成refreshToken
     * @param subject
     * @return
     */
    public String generateRefreshToken(String subject) {
        return generate(subject, refreshTokenExpiration);
    }

    /**
     * 生成JWT
     * @param subject 用户名
     * @return JWT
     */
    private String generate(String subject, Duration expiration) {
        // 过期时间
        Date expiryDate = new Date(System.currentTimeMillis() + expiration.toMillis());

        return Jwts.builder()
                .setSubject(subject) // 将用户名放进JWT
                .setIssuedAt(new Date()) // 设置JWT签发时间
                .setExpiration(expiryDate)  // 设置过期时间
                .signWith(SignatureAlgorithm.HS512, secretKey) // 设置加密算法和秘钥
                .compact();
    }

    /**
     * 刷新token
     * @param token
     * @param refreshDate
     * @return
     */
    public String refreshToken(String token, Date refreshDate) {
        Claims claims = parse(token);
        if (claims == null) {
            return "";
        }
        return Jwts.builder()
                .setSubject(claims.getSubject()) // 将用户名放进JWT
                .setIssuedAt(new Date()) // 设置JWT签发时间
                .setExpiration(refreshDate)  // 设置过期时间
                .signWith(SignatureAlgorithm.HS512, secretKey) // 设置加密算法和秘钥
                .compact();
    }

    /**
     * 解析JWT
     * @param token JWT字符串
     * @return 解析成功返回Claims对象，解析失败返回null。不管是否过期，都返回claims对象
     */
    public Claims parse(String token) {
        Logger logger = LogManager.getLogger("token");
        // 如果是空字符串直接返回null
        if (!StringUtils.hasLength(token)) {
            return null;
        }

        Claims claims = null;
        // 解析失败了会抛出异常，token过期、token非法都会导致解析失败
        try {
            claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException expiredJwtException) {
            logger.warn("token已过期");
            claims = expiredJwtException.getClaims();
        } catch (JwtException jwtException) {
            logger.error("token无效");
        }
        return claims;
    }

    /**
     * 判断token是否过期
     * @param token
     * @return
     */
    public Boolean tokenExpired(String token) {
        Claims claims = parse(token);
        Date expiration = claims.getExpiration();
        // 和当前时间进行对比来判断是否过期
        return new Date(System.currentTimeMillis()).after(expiration);
    }
}
